package com.weilele.mvvm.widget

import android.content.Context
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.PixelFormat
import android.graphics.PorterDuff
import android.util.AttributeSet
import android.view.SurfaceHolder
import android.view.SurfaceView
import android.view.ViewGroup
import com.weilele.mvvm.logI
import com.weilele.mvvm.utils.coroutine.createCoroutine
import kotlinx.coroutines.*
import java.lang.Runnable
import java.util.concurrent.Executors

/**
 * SurfaceView结合协程
 * 会自动恢复之前的状态
 * 子类只需要专心处理自己的逻辑
 */
abstract class BaseSurfaceView : SurfaceView {
    //协程作用域
    private var coroutineScope: CoroutineScope? = null

    //绘制工作，可取消
    //活跃状态为false。异常结束，启动的时候应该恢复
    //null 正常结束
    //true 正在运行
    private var drawJob: Job? = null

    constructor(context: Context) : this(context, null)
    constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)
    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(
            context,
            attrs,
            defStyleAttr
    ) {
        holder.addCallback(call)
    }

    private val call = object : SurfaceHolder.Callback2 {
        override fun surfaceRedrawNeeded(holder: SurfaceHolder) {
            //设置SurfaceView透明。
            holder.setFormat(PixelFormat.TRANSLUCENT)
            drawOnUi(holder)
        }

        override fun surfaceRedrawNeededAsync(holder: SurfaceHolder, drawingFinished: Runnable) {
            super.surfaceRedrawNeededAsync(holder, drawingFinished)
            //设置SurfaceView透明。
            holder.setFormat(PixelFormat.TRANSLUCENT)
            if (isEnableDrawJob) {
                getScope().launch { startDraw(this) }
            }
        }

        override fun surfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) {
        }

        override fun surfaceDestroyed(holder: SurfaceHolder) {
            cancelScope()
        }

        override fun surfaceCreated(holder: SurfaceHolder) {
            //设置SurfaceView透明。
            holder.setFormat(PixelFormat.TRANSLUCENT)
            drawOnUi(holder)
            checkLatsStatus()
        }
    }


    /**
     * 执行锁定画布，绘制，释放画布
     */
    @Synchronized
    private suspend fun startDraw(coroutineScope: CoroutineScope) {
        val mHolder = holder
        if (mHolder == null || mHolder.surface?.isValid != true) {
            delay(100)
        } else {
            mHolder.lockCanvas()?.let { lockCanvas ->
                coroutineScope.drawOnThread(lockCanvas)
                mHolder.unlockCanvasAndPost(lockCanvas)
            }
        }
    }

    /**
     * 子线程绘制完之后推送到主线程
     */
    abstract suspend fun CoroutineScope.drawOnThread(canvas: Canvas)

    /**
     * 主线程绘制，自己处理逻辑，这里只是再合适的时机调用
     */
    open fun drawOnUi(canvas: SurfaceHolder) {}


    /**
     * 子线程是否循环绘制
     * 是，子线程无线循环，已经处理自动取消
     */
    abstract fun isDrawOnThreadLoop(): Boolean

    private var isAttachedWindow = false
    override fun onDetachedFromWindow() {
        isAttachedWindow = false
        cancelScope()
        super.onDetachedFromWindow()
    }

    override fun onAttachedToWindow() {
        super.onAttachedToWindow()
        isAttachedWindow = true
        checkLatsStatus()
    }

    private fun checkLatsStatus() {
        if (drawJob != null) {
            startJob()
        }
    }


    /**
     * 取消协程,
     * 一般为异常取消，不将之前的值置为null
     */
    private fun cancelScope() {
        drawJob?.cancel()
        coroutineScope?.cancel()
        coroutineScope = null
    }

    /**
     * 创建一个协程
     */
    private fun getScope(): CoroutineScope {
        //创建单线程模式，不然会导致报错
        val scope = coroutineScope
                ?: createCoroutine(Executors.newSingleThreadExecutor().asCoroutineDispatcher())
        coroutineScope = scope
        return scope
    }

    /**********************************************对外开放接口************************************************/
    /**
     * 是否可以执行绘制
     * 默认为false 自己可以在一个合适的机会去调用
     *
     */
    var isEnableDrawJob = false
        set(value) {
            field = value
            if (!value) {
                stopJob()
            }
        }

    fun startJob() {
        if (isEnableDrawJob) {
            if (drawJob != null && drawJob?.isActive == true) {
                return
            }
            drawJob = getScope().launch {
                if (isDrawOnThreadLoop()) {
                    while (isActive && drawJob != null) {
                        if (isAttachedWindow) {
                            startDraw(this)
                        } else {
                            delay(32)
                        }
                    }
                } else {
                    startDraw(this)
                }
            }
        }
    }

    fun stopJob() {
        //加个判断，防止多次取消
        if (drawJob != null && drawJob?.isActive == true) {
            drawJob?.cancel()
        }
        drawJob = null
    }

    /**
     * 清空画布
     */
    fun clearCanvas(canvas: Canvas?) {
        canvas?.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR)
    }
}